package com.kehutong.department.service;

import java.util.*;
import java.util.stream.Collectors;

import com.kehutong.common.DoveClient;
import com.kehutong.common.entity.TreeUtil;
import com.kehutong.common.enums.Gender;
import com.kehutong.common.permission.DataPermissionQuery;
import com.kehutong.common.permission.UserLoginInfo;
import com.kehutong.common.util.Token;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.http.Bean;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.mvc.webservice.WebService;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.util.Objects;

import com.kehutong.common.entity.Root;
import com.kehutong.department.entity.Department;
import org.coraframework.util.UUIDGenerator;

/**
 * 部门服务
 *
 * @author liuzhen(liuxing521a@163.com)
 * @createTime 2021年3月06日下午6:16:25
 */
@WebService("/basic/department/service")
public class DepartmentService {
	private static final Logger logger = LoggerFactory.getLogger(DepartmentService.class);
	@Inject
	private JdbcSession jdbcSession;
	@Inject
	private DoveClient doveClient;

	@ReqMapping("/list")
	public Object list(JSONObject json) {
		List<Department> list = jdbcSession.findArray(Department.class)
				.eq(json, "parent_id")
				.like(json, "parent_ids", "name")
				.in(json, "id")
				.exe();

		list.forEach(dep ->{
			List<String> departmentName = new ArrayList<>();
			dep.getParent_ids().forEach(id->{
				if(!id.equals("1")){
					Department department = Pool.get(Department.class, id);
					departmentName.add(department.getName());
				}
			});
//			departmentName.add(dep.getName());
			dep.setParent_names(String.join("-", departmentName));
		});

		return list;
	}

	@ReqMapping("/PageList")
	public Object PageList(JSONObject json) {
		logger.debug("{}=========", this.hashCode());
		Page<Department> page = jdbcSession.findPage(Department.class)
				.in(json, "id")
		      .page(json).exe();
		page.getList().forEach(dep ->{
			List<String> departmentName = new ArrayList<>();
			dep.getParent_ids().forEach(id->{
				if(!id.equals("1")){
					Department department = Pool.get(Department.class, id);
					departmentName.add(department.getName());
				}
			});
			departmentName.add(dep.getName());
			dep.setParent_names(String.join("-", departmentName));
		});

		return page;
	}

	@ReqMapping("/getChildDepartments")
	public Object getChildDepartments(JSONObject json) {
		Set<String> idList = new HashSet<>();
		JSONArray pidList =	json.getJSONArray("pidList");
		for (int i = 0; i < pidList.size(); i++) {
			Department data = Pool.get(Department.class, pidList.get(i).toString());
			idList.addAll(data.getParent_ids());
		}
		return idList;
	}

	@ReqMapping("/disposeDepartment")
	public Object disposeDepartment(JSONObject json) {
		List<String> departments = JSONObject.parseArray(json.getJSONArray("departments").toString(),String.class);

		List<Department> data = jdbcSession.findArray(Department.class)
				.eq("deleted", false)
				.exe();

		Map<String,Department> departmentMap = new HashMap<>();
		data.forEach(item->{
			String name = item.getName();
			String parent_id = item.getParent_id();
			String key = name + "-" + parent_id;
			departmentMap.put(key, item);
		});

		for (String item: departments) {
			List<String> items = Arrays.asList(item.split(","));
			for (String dep: items) {
				List<String> deps = Arrays.asList(dep.split("-"));
				String pid = Root.ROOT_ID;
				List<String> ids = new ArrayList<>();
				for (String name: deps) {
					//  查询到组织部门
					Department depItem = departmentMap.get(name + "-" + pid);
					if (Objects.isNull(depItem)) {
						// 未获取到部门信息 则新增部门
						ids.add(pid);
						depItem = Pool.newInstance(Department.class);
						depItem.setName(name);
						depItem.setParent_id(pid);
						depItem.setParent_ids(ids);
						jdbcSession.insert(depItem);

						//插入到list
						data.add(depItem);

						//插入到map
						departmentMap.put(name + "-" + pid, depItem);

						pid = depItem.getId();
					} else {
						ids = depItem.getParent_ids();
						ids.add(pid);
						pid = depItem.getId();
					}
				}
			}
		}

		return Result.success(data);
	}

	@ReqMapping("/get")
	public Object get(String id) {
		Department item = jdbcSession.findById(Department.class, id);
		if (Objects.nonNull(item) && item.isDeleted()) {
			return Result.success();
		}

		return item;
	}

	@Bean(newInstance = true, copy = true)
	@ReqMapping("/save")
	public Object save(Department item) throws Exception {
		// todo 需要添加验证
		if (Objects.isEmpty(item.getPid())) {
			item.setId(Root.ROOT_ID);
		}
		jdbcSession.insert(item);
		return Result.success(item);
	}

	@ReqMapping("/ThridSave")
	public Object ThridSave(JSONObject json) throws Exception {
		Department item = Pool.newInstance(Department.class);
		if(json.getString("id")!=null){
			item.setId(json.getString("id"));
		}
		item.setParent_id(json.getString("parent_id"));
		List<String> parent_ids=   JSONObject.parseArray(json.getJSONArray("parent_ids").toJSONString(), String.class);
		item.setParent_ids(parent_ids);
		item.setName(json.getString("name"));
		jdbcSession.insert(item);
		return Result.success(item);
	}

	@ReqMapping("/ThridUpdate")
	public Object ThridUpdate(JSONObject json) throws Exception {
		Department item = Pool.newInstance(Department.class);
		item.setParent_id(json.getString("parent_id"));
		List<String> parent_ids=JSONObject.parseArray(json.getJSONArray("parent_ids").toJSONString(), String.class);
		item.setParent_ids(parent_ids);
		item.setParent_ids(parent_ids);
		item.setName(json.getString("name"));
		item.setId(json.getString("id"));
		jdbcSession.updateById(item);
		return Result.success(item);
	}
	@Bean(copy = true)
	@ReqMapping("/update")
	public Object update(Department item) throws Exception {
		// todo 需要添加验证
		jdbcSession.updateById(item);
		return Result.success();
	}

	/**
	 * 内建模式本地新增完成后更新部门主键
	 * @param json
	 * @return
	 * @throws Exception
	 */
	@Bean(copy = true)
	@ReqMapping("/updateIdByInner")
	public Object updateIdByInner(JSONObject json) throws Exception {
		String oldId = json.getString("oldId");
		String newId = json.getString("newId");
		//解决如果部门统一级别逻辑删除,后面重新创建一个名字一样的部门，腾讯同一级别同一名字部门ID一样
		List<Department> departmentList=jdbcSession.findArray(Department.class).eq("id",newId).exe();
		if(Objects.nonEmpty(departmentList)){
			jdbcSession.deleteById(departmentList);
		}
		Department item = Pool.get(Department.class,oldId);
		item.setId(newId);
		jdbcSession.updateById(item,oldId);
		return Result.success();
	}

	@ReqMapping("/updateEmployee")
	public Object updateEmployee(JSONObject json){
		JSONArray oldIds = json.getJSONArray("oldIds");
		if(Objects.nonEmpty(oldIds)){
			oldIds.forEach(oldId ->{
				Department item = Pool.get(Department.class, String.valueOf(oldId));
				List<String> department = item.getEmployeeIds();
				department.remove(json.getString("employeeId"));
				item.setEmployeeIds(new ArrayList<>(department));

				List<String> departmentName = item.getEmployeeNames();
				departmentName.remove(json.getString("employeeName"));
				item.setEmployeeNames(new ArrayList<>(departmentName));
				jdbcSession.updateById(item);
			});
		}

		JSONArray ids = json.getJSONArray("ids");
		if(Objects.nonEmpty(ids)){
			ids.forEach(id->{
				Department item = Pool.get(Department.class, String.valueOf(id));
				Set<String> empIds = new HashSet<>(item.getEmployeeIds());
				empIds.add(json.getString("employeeId"));
				item.setEmployeeIds(new ArrayList<>(empIds));

				Set<String> empNames = new HashSet<>(item.getEmployeeNames());
				empNames.add(json.getString("employeeName"));
				item.setEmployeeNames(new ArrayList<>(empNames));
				jdbcSession.updateById(item);
			});
		}
		return Result.success();
	}

	@ReqMapping("/ThriddeleteAll")
	public Object ThriddeleteAll() throws Exception {
		List<Department> DepartmentList=jdbcSession.findArray(Department.class).exe();
		if(DepartmentList!=null && DepartmentList.size()>0){
			for(Department thirdDepartment:DepartmentList){
				jdbcSession.deleteById(thirdDepartment);
			}
		}
		return Result.success();
	}
	@ReqMapping("/delete")
	public Object delete(Department item) throws Exception {
		if (Objects.nonNull(item)) {
			item.setDeleted(true);
			jdbcSession.updateById(item);
		}

		return Result.success();
	}

	@ReqMapping("/saveBatch")
	public Object saveBatch(JSONArray departments) {
		for (int i = 0; i < departments.size(); i ++) {
			JSONObject jsonObject = departments.getJSONObject(i);
			//公司模板 0.第三方 1.内建
			String pattern=jsonObject.getString("pattern");
			String id = jsonObject.getString("id");
			Department department = jdbcSession.findById(Department.class, id);
			if (Objects.isNull(department)) {
				department = Pool.newInstance(Department.class, id);
				department.setName(jsonObject.getString("name"));
				department.setThirdName(jsonObject.getString("name"));
				department.setSort(jsonObject.getIntValue("sort"));
				department.setParent_id(jsonObject.getString("parent_id"));
				department.setParent_ids(getParentIds(department.getParent_id(),id));
				jdbcSession.insert(department);
			} else {
				//内建模式补充部门名称
				if(Objects.nonNull(pattern) && Objects.equal("1",pattern)){
					department.setName(jsonObject.getString("name"));
				}
				department.setThirdName(jsonObject.getString("name"));
				department.setSort(jsonObject.getIntValue("sort"));
				department.setParent_id(jsonObject.getString("parent_id"));
				department.setParent_ids(getParentIds(department.getParent_id(),id));
				jdbcSession.updateById(department);
			}
		}

		return Result.success();
	}

	public Object doGetDepartmentEmployeeCreateRoot(Token token){
		JSONArray data = new JSONArray(2);

		FindArray<Department> find = jdbcSession.findArray(Department.class)
				.eq("deleted", false)
				.order("sort", "desc");

		DataPermissionQuery.setManageDepartmentNoDataSql(find, null);

		List<Department> departments = find.exe();

		Map<String, Department> treeMap = TreeUtil.asMapById(departments);

		Set<String> tokenDepartments = new HashSet<>(token.getDepartments());
		UserLoginInfo userLoginInfo = DataPermissionQuery.getUserInfo(null);
		tokenDepartments.addAll(userLoginInfo.getManageDepartmentNo());

		for (String id : tokenDepartments) {
			Department dep = Pool.get(Department.class, id);
			treeMap.put(dep.getId(), dep);
		}

		Department department = TreeUtil.organizeAsTree(treeMap, false);
		if (Objects.nonNull(department)) {
			JSONObject root = department2JSONObject(department);
			List<JSONObject> array = new ArrayList<>();
			department.getChildList().forEach(item->{
				array.add(department2JSONObject(item));
			});

			data.add(root);
			data.add(array);
			return Result.success(data);
		}

		List<Department> fisrtChildList = new ArrayList<>();

		for (String id : tokenDepartments) {
			Department dep = treeMap.get(id);
			fisrtChildList.add(dep);
		}

		department = Pool.newInstance(Department.class, "a");
		department.setName(token.getCompanyName());

		List<JSONObject> array = new ArrayList<>();
		fisrtChildList.forEach(item->{
			array.add(department2JSONObject(item));
		});

		JSONObject root = department2JSONObject(department);
		root.put("isCreateRoot", true);
		data.add(root);
		data.add(array);
		return Result.success(data);
	}

	public Object doGetDepartmentEmployee(JSONObject jsonObject) throws Exception {
		JSONArray data = new JSONArray(2);

		Department department = Pool.get(Department.class, jsonObject.getString("parent_id"));
		FindArray<Department> find =  jdbcSession.findArray(Department.class)
				.eq("parent_id", department.getId())
				.eq("deleted", false);
		List<Department> departments = find.exe();

		List<String> departmentIds = new ArrayList<>();
		departments.forEach(item->{
			departmentIds.add(item.getId());
		});
		departmentIds.add(department.getId());

		JSONArray employees = new JSONArray();
		if(jsonObject.getBoolean("isEmp")){
			employees = getEmployees(departmentIds);
		}

		List<JSONObject> array = new ArrayList<>();
		departments.forEach(item->{
			array.add(department2JSONObject(item));
		});

		List<String> ids = employees.stream().map(item -> {
			JSONObject d = (JSONObject) item;
			return d.getString("id");
		}).collect(Collectors.toList());

		Map<String ,JSONObject> employeeMap = getEmployeeMap(ids);

		employees.forEach(item-> {
			JSONObject employee = (JSONObject) item;
			if(employee.getJSONArray("department").contains(department.getId())){
				array.add(employee2JSONObject(department.getId(), employee, employeeMap));
			}
		});

		JSONObject root = department2JSONObject(department);
		root.put("isCreateRoot", false);
		data.add(root);
		data.add(array);
		return Result.success(data);
	}

	private JSONObject employee2JSONObject(String departmentId, JSONObject employee, Map<String, JSONObject> employeeMap) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("id", employee.getString("id"));

		JSONObject json = employeeMap.get(employee.getString("id"));
		if(Objects.nonNull(json)){
			jsonObject.put("avatar", json.getString("avatar"));
		}
		jsonObject.put("pid", departmentId);
		jsonObject.put("label", employee.getString("name"));
		jsonObject.put("user", true);
		return jsonObject;
	}

	public JSONObject employee2JSONObject(String departmentId, JSONObject employee) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("id", employee.getString("id"));
		jsonObject.put("pid", departmentId);
		jsonObject.put("label", employee.getString("name"));
		jsonObject.put("user", true);
		return jsonObject;
	}

	public JSONArray getEmployees(List<String> departments) throws Exception {

		JSONObject result = doveClient.post("/basic/employee/service/list", http->{
			JSONObject body = new JSONObject();
			if(Objects.nonNull(departments)){
				body.put("department", departments);
			}

			body.put("pageNo", 1);
			body.put("pageSize", 1000000);

			http.setBody(body.toString());
		});

		JSONArray data = result.getJSONObject("data").getJSONArray("list");

		if (Objects.isNull(data)) {
			return null;
		}

		return data;
	}

	public void updateDutyDepartment(Department department) throws Exception{
		Department old = Pool.get(Department.class, department.getId());

		doveClient.post("/basic/employee/service/updateDutyDepartment", http -> {
			JSONObject body = new JSONObject();
			body.put("ids", department.getEmployeeIds());
			if(Objects.nonNull(old)){
				body.put("oldIds", old.getEmployeeIds());
			}
			body.put("department", department.getId());
			body.put("departmentName", department.getName());
			http.setBody(body.toJSONString());
		});
	}

	public JSONArray getHouses() throws Exception {
		JSONObject result = doveClient.post("/basic/house/service/list", http->{});

		JSONArray data = result.getJSONArray("data");

		if (Objects.isNull(data)) {
			return null;
		}

		return data;
	}

	public JSONArray getCommunityByIds() throws Exception {
		JSONObject result = doveClient.post("/basic/community/service/list", http->{});

		JSONArray data = result.getJSONArray("data");

		if (Objects.isNull(data)) {
			return null;
		}

		return data;
	}

	private Map<String, JSONObject> getEmployeeMap(List<String> employeeIds) throws Exception{
		JSONObject result = doveClient.post("/kht-bin/wwout/getEmployeeByKhtIds",(http)->{
			JSONObject body = new JSONObject();
			body.put("khtIds", employeeIds);
			http.setBody(body.toJSONString());
		});

		Map<String,JSONObject> employeeMap = new HashMap<>();
		if (result.getIntValue("code") == 200) {
			JSONArray data = result.getJSONArray("data");
			data.forEach(item->{
				JSONObject obj = (JSONObject) item;
				employeeMap.put(obj.getString("khtid"), obj);
			});
		}

		return employeeMap;
	}

	@ReqMapping("/listAll")
	public Object listAll(String departments) {
		if (Objects.isEmpty(departments)) {
			return jdbcSession.findArray(Department.class)
					.eq("deleted", false)
					.exe();
		}

		String[] str = departments.split(",");
		return jdbcSession.findArray(Department.class)
				.in("id", Arrays.asList(str))
				.eq("deleted", false)
				.exe();
	}

	@ReqMapping("/saveDepartment")
	public Object saveDepartment(JSONObject jsonObject) {
		JSONArray jsonArray = jsonObject.getJSONArray("data");
		for (int i = 0; i < jsonArray.size(); i ++) {
			JSONObject json = jsonArray.getJSONObject(i);
			Department department = Pool.get(Department.class, json.getString("id"));
			department.setMemCount(json.getIntValue("count"));
			department.setEmployeeIds(fromJsonArray(json.getJSONArray("leadIds")));
			department.setEmployeeNames(fromJsonArray(json.getJSONArray("leadNames")));
			jdbcSession.updateById(department);
		}

		//更新部门所有上级id
		List<Department> departmentList=jdbcSession.findArray(Department.class)
				.eq("deleted", false)
				.exe();
		Department isExitRoot = jdbcSession.findById(Department.class,Root.ROOT_ID);
		if(Objects.isNull(isExitRoot)){
			departmentList.add(Pool.newInstance(Department.class,Root.ROOT_ID));
		}
		Department root= TreeUtil.organizeAsTree(departmentList,false);
		setParent(root, root.getChildList());
		jdbcSession.updateById(departmentList);

		return Result.success();
	}

	private static void setParent(Department parent, List<Department> childList) {
		for (Department dpt : childList) {
			dpt.setParent_id(parent.getId());
			dpt.setParent_ids(toList(parent.getParent_ids(), parent.getId(),dpt));
			if(dpt.getChildList()!=null){
				setParent(dpt, dpt.getChildList());
			}
		}
	}

	private static  List<String> toList(List<String> pids, String pid,Department dpt) {
		if (Root.isRoot(pid)) {
			List<String> list = new ArrayList<>();
			list.add(pid);
			list.add(dpt.getId());
			return list;
		}

		List<String> list = new ArrayList<>(pids.size() +1);
		list.addAll(pids);
		list.add(dpt.getId());
		return list;
	}

	private List<String> getParentIds(String pid,String id) {
		List<String> list = new ArrayList<>(8);

		Department department = jdbcSession.findById(Department.class, pid);
		while (Objects.nonNull(department)) {
			list.add(0, department.getId());
			department = jdbcSession.findById(Department.class, department.getParent_id());
		}
		list.add(id);
		return list;
	}

	public JSONObject department2JSONObject(Department department) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("id", department.getId());

		List<String> ids = department.getParent_ids();
		jsonObject.put("pid", ids);

		List<String> pname = new LinkedList<>();
		if(Objects.nonEmpty(ids)){
			ids.forEach(id->{
				Department item = Pool.get(Department.class, id);
				if(Objects.nonNull(item)){
					pname.add(item.getName());
				}
			});
		}
		jsonObject.put("pname", pname);
		jsonObject.put("label", department.getName());

		List<Department> list =  jdbcSession.findArray(Department.class)
				.eq("parent_id", department.getId())
				.eq("deleted", false)
				.exe();
		jsonObject.put("count", list.size());

		return jsonObject;
	}

	private List<String> fromJsonArray(JSONArray aray) {
		List<String> strList = new ArrayList<>(aray.size());
		for (int i = 0; i < aray.size(); i ++) {
			strList.add(aray.getString(i));
		}
		return strList;
	}

	public void setParentIds(Department item){
		List<Department> departments = jdbcSession.findArray(Department.class)
				.eq("parent_id", item.getId())
				.exe();

		List<String> parent_ids = item.getParent_ids();
		parent_ids.add(item.getId());

		for (Department dept: departments) {
			dept.setParent_ids(parent_ids);
			jdbcSession.updateById(dept);

			setParentIds(dept);
		}
	}
}
